home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / Drag_on Modules / hAWK programs / $hAWK_to_Cd2 < prev    next >
Encoding:
Text File  |  1993-04-17  |  40.3 KB  |  2,069 lines  |  [TEXT/KEEN]

  1. #$hAWK_to_Cd2 : goal is to translate a hAWK program into C.
  2. ######## INCOMPLETE ############, and still very much under development
  3. #Run it on a copy of one of your hAWK programs if you're curious
  4. #to see what it does, but don't be too disappointed if the translation
  5. #to C is less than perfect. There is very little error checking at this
  6. #stage, and the run-time package that will actually execute the output
  7. #from this program (after it is compiled with THINK C) doesn't exist yet.
  8.  
  9. #Although this program doesn't yet do anything useful, in it you'll
  10. #find a fairly complete lexer and parser for hAWK. The parser is of
  11. #the hand-coded recursive-descent type, and can be compared with
  12. #the YACC-style parser in AWKTAB.C/Y if you're interested in the inner
  13. #workings of hAWK.
  14.  
  15. #Some issues are not yet resolved, and the final version of this
  16. #program may be rather different. At present, it's doing a decent job
  17. #and hasn't locked up in quite a while. Pass it one hAWK program as input,
  18. #and look for output in files with the same name but ending in '.c' and '.h'.
  19.  
  20. # User’s Manual references:
  21. # «hAWK User’s Manual» «F   Running hAWK programs»
  22. # «hAWK User’s Manual» «L  5   Regular expressions»
  23. # «hAWK User’s Manual» «M  5   Built-in string and file functions»
  24. # «hAWK User’s Manual» «K  4   Built-in variables»
  25. # «hAWK User’s Manual» «K  8   Arrays»
  26. # «hAWK User’s Manual» «N   User-defined functions»
  27. # «hAWK User’s Manual» «P  3   The getline function»
  28. # «hAWK User’s Manual» «O  3   Output into files»
  29. # «hAWK User’s Manual» «Q   The hAWK function»
  30.  
  31.  
  32. BEGIN {    didNL = 1; # fudge for first time only
  33.         num_constants = 0
  34.         loosePrint = 0
  35.         # Construct file names
  36.         z = split(ARGV[1], names, ":")
  37.         filename = names[z];
  38.         sub(/^$/, "", filename)
  39.         filename = substr(filename, 1, 29)
  40.         outfileC = filename ".c"
  41.         for (i = z-1; i >= 1; --i) #note i = z gives the input file name proper
  42.             outfileC = names[i] ":" outfileC;#put path in front of outfile name
  43.         len = length(outfileC) - 1
  44.         outfileH = substr(outfileC, 1, len)
  45.         outfileH = outfileH "h"
  46.         outfileF = substr(outfileC, 1, len)
  47.         outfileF = outfileF "f"
  48.         outfileB = substr(outfileC, 1, len)
  49.         outfileB = outfileB "b"
  50.         outfileE = substr(outfileC, 1, len)
  51.         outfileE = outfileE "z"
  52.         outfile = outfileC
  53.         
  54.         init_toktypes() # for multi-char tokens
  55.         init_tables() #builtin functions, keywords
  56.         
  57.         translate()
  58.         filename = filename ".c"
  59.         print_instructions()
  60.         }
  61.  
  62. function print_instructions()
  63.     {
  64. print "Entering"" print_instructions"
  65.     print "Output is in"
  66.     print outfileC
  67.     print "and"
  68.     print outfileH
  69.     print ""
  70.     print "Install", filename, "as the bottom-most file in"
  71.     print "the THINK C project \"hAWK_to_C.π\", then \"Update\""
  72.     print "and \"Build Code Resource\" to the folder \"Chawk programs\"."
  73.     print ""
  74.     print "To run your new compiled program, start up your favourite"
  75.     print "Drag_on Module - compatible editor, select \"Chawk\" from"
  76.     print "a menu, and then pick your new program from the \"Program\""
  77.     print "popup menu in the resulting dialog."
  78.     }
  79.  
  80. #advance(), the lexical analyzer;
  81. #    Removes white space, but notices newlines
  82. #    Puts next token in tok, removes it from current input line
  83. #    At end of file, returns "(eof)"
  84. #    Note toktype is set to a special UPPERCASE token type only for
  85. #     names, numbers, or other things longer than one char; else
  86. #    being only a single char, toktype is set to the char.
  87. #    This includes "~" and "=" and "*" for example, but excludes
  88. #    single-letter names, and also numbers.
  89. #NOTE CONCAT_OP is inferred by two exps jammed together, space
  90. #in between is not required, eg "hello""there"
  91. function advance(    temp, in_bracket, c,r)
  92.     {
  93. print "Entering"" advance"
  94. print "Previous token:", tok
  95. print "Line:", line
  96.     if (toktype == EOF) return
  97.     if (nextTok != "") #use lookahead
  98.         {
  99.         tok = nextTok
  100.         toktype = nextTokType
  101.         nextTok = ""
  102.         return
  103.         }
  104.     sub(/^[ \t]+/, "", line) #remove leading white
  105.     if (match(line, /^#/)) #kill if comment
  106.         {
  107.         line = substr(line,2)
  108.         gen("/*" line "*/")
  109.         line = ""
  110.         }
  111.     while (length(line) == 0)
  112.         {
  113.         if (!didNL)
  114.             {
  115.             didNL = 1
  116.             toktype = NEWLINE
  117.             tok = "\n"
  118.             return
  119.             }
  120.         else
  121.             didNL = 0;
  122.         if (getline line == 0)
  123.             {
  124.             toktype = EOF
  125.             tok = "(eof)"
  126.             return
  127.             }
  128.         # line continuation
  129.         while (match(line, /\\$/))
  130.             {
  131.             getline temp
  132.             line = substr(line, 1, length(line)-1) temp
  133.             }
  134.         #immediately remove comments and leading white
  135.         sub(/^[ \t]+/, "", line) #remove leading white
  136.         if (match(line, /^#/)) #kill if comment
  137.             {
  138.             line = substr(line,2)
  139.             gen("/*" line "*/")
  140.             line = ""
  141.             }
  142.         }
  143.     if (want_regexp) #just saw "/" when wanted
  144.         {
  145.         #wrinkles: watch for \/ and / inside []
  146.         #TO DO line continuation and newline - see AWK.Y
  147.         toktype = REGEXP
  148.         while ((c = substr(line,1,1)) != "")
  149.             {
  150.             if (!in_bracket && c == "/")
  151.                 {
  152.                 line = substr(line, 2) #skip closing /
  153.                 tok = r
  154.                 return
  155.                 }
  156.             if (c == "\\")
  157.                 {
  158.                 r = r c
  159.                 line = substr(line, 2)
  160.                 c = substr(line,1,1)
  161.                 }
  162.             else if (c == "[")
  163.                 in_bracket = 1
  164.             else if (c == "]")
  165.                 in_bracket = 0
  166.             r = r c
  167.             line = substr(line, 2)
  168.             }
  169.         error("Couldn't find end of regular expression")
  170.         }
  171.     if (match(line, /^[A-Za-z_](\w|_)*/))        #identifier
  172.         {
  173.         tok = substr(line, 1, RLENGTH)
  174.         line = substr(line, RLENGTH+1)
  175.         if (tok == "print")
  176.             toktype = LEX_PRINT
  177.         else if (tok == "printf")
  178.             toktype = LEX_PRINTF
  179.         else if (tok == "getline")
  180.             toktype = LEX_GETLINE
  181.         else if (tok in hAWK_BUILTIN)
  182.             toktype = LEX_BUILTIN
  183.         else if (tok in hAWK_LENGTH)
  184.             toktype = LEX_LENGTH
  185.         else if (tok in hAWK_KEY)
  186.             toktype = KEY
  187.         #Wrinkle; is it immediately followed by a "("?
  188.         else if (substr(line, 1, 1) == "(")
  189.             toktype = FUNC_CALL
  190.         else
  191.             toktype = NAME
  192.         return
  193.         }
  194.     if (match(line, /^([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?/))    #number
  195.         toktype = NUMBER
  196.     ##else if (match(line, /^".*([^\\]?|(\\\\)+)"/))        #string
  197.     else if (match(line, /^"[^"]*"/))        #string
  198.         {
  199.         toktype = YSTRING
  200.         if (index(line, "\\"))
  201.             {
  202.             painfully_match_string()
  203.             return
  204.             }
  205.         }
  206.     else if (match(line, /^>>/))                        #redir append
  207.         toktype = APPEND_OP
  208.     else if (match(line, /^(<=|==|!=|>=)/))                #relational
  209.         toktype = RELOP
  210.     else if (match(line, /^\+\+/))
  211.         toktype = INCREMENT
  212.     else if (match(line, /^--/))
  213.         toktype = DECREMENT
  214.     else if (match(line, /^(\+=|-=|\*=|\/=|\^=|%=)/))#assign, inc
  215.         toktype = ASSIGNOP
  216.     else if (match(line, /^&&/))
  217.         toktype = LEX_AND
  218.     else if (match(line, /^\|\|/))
  219.         toktype = LEX_OR
  220.     else if (match(line, /^!~/))
  221.         toktype = MATCHOP
  222.     else if (match(line, /^./))                            #everything else
  223.         {
  224.         #TO DO trap illegal tokens, eg "@"
  225.         toktype = substr(line,1,1)
  226.         }
  227.     else
  228.         error("Unexpected empty line")
  229.     tok = substr(line, 1, RLENGTH)
  230.     line = substr(line, RLENGTH+1)
  231.     }
  232.  
  233. function painfully_match_string(    c, esc, i, len)
  234.     {
  235.     esc = 0
  236.     len = length(line)
  237.     for (i = 2; i <= len; ++i)
  238.         {
  239.         c = substr(line,i,1)
  240.         if (c == "\"")
  241.             {
  242.             if (esc == 0 || esc%2 == 0)
  243.                 break;
  244.             else
  245.                 esc = 0
  246.             }
  247.         else if (c == "\\")
  248.             ++esc
  249.         else
  250.             esc = 0
  251.         }
  252.     if (i > len)
  253.         error("string has no end in line ")
  254.     tok = substr(line, 1, i)
  255.     line = substr(line, i+1)
  256.     }
  257.  
  258. #Single lookahead, preserving current tok and toktype,
  259. #sets nextTok to token, and nextTokType to type.
  260. function lex_next(        oldTok, oldTokType)
  261.     {
  262. print "Entering"" lex_next"
  263.     if (nextTok != "")
  264.         return
  265.     oldTok = tok
  266.     oldTokType = toktype
  267.     advance()
  268.     nextTok = tok
  269.     nextTokType = toktype
  270.     tok = oldTok
  271.     toktype = oldTokType
  272.     }
  273.  
  274. #print s with nt leading tabs
  275. # Four possible destinations:
  276. #    -outfileC, all patterns/actions
  277. #    -outfileF, all function definitions
  278. #    -outfileB/E, BEGIN, END
  279. #    Note code for global defs and prototypes is stored
  280. #    in array before printing to outfileH. At end, the
  281. #    T/B/E files are appended to outfileC, and outfileH
  282. #    is included always at top of outfileC
  283. function gen(s)
  284.     {
  285. print "Entering"" gen"
  286.     printf("%s%s\n", substr("\t\t\t\t\t\t\t\t\t", 1, nt), s) > outfile
  287.     }
  288.  
  289. #not used
  290. function gen_no_slashn(s)
  291.     {
  292. print "Entering"" gen_no_slashn"
  293.     printf("%s%s", substr("\t\t\t\t\t\t\t\t\t", 1, nt), s) > outfile
  294.     }
  295.  
  296.  
  297. #read next token if s == tok
  298. function eat(s)
  299.     {
  300. print "Entering"" eat"
  301.     if (tok != s) error("expected " s)
  302.     advance()
  303.     }
  304.  
  305. #absorb optional newlines
  306. function newline()
  307.     {
  308. print "Entering"" newline"
  309.     while (tok == "\n")
  310.         advance()
  311.     }
  312.  
  313. function error(s)
  314.     {
  315.     print "Error:", s
  316.     print "Location:", names[z], NR
  317.     print "Current Line:", line
  318.     print "Current token", tok
  319.     print "Current toktype:", toktype
  320.     exit 1
  321.     }
  322.  
  323. ############ the parser proper ###############
  324.  
  325. function translate()
  326.     {
  327. print "Entering"" translate"
  328.     advance() # done first to emit any top comments
  329.     newline() #also to get opening comments
  330.     ##while (toktype != EOF)
  331.     ##    {
  332.     ##    print tok, toktype
  333.     ##    advance()
  334.     ##    }
  335.     ##return
  336.     
  337.     gen("")
  338.     boiler_plate() #open up the output files
  339.     nt = 2
  340.     start()
  341.     gen("END_GETREC:") #for "next" jumps
  342.     gen("}") # end of while getrec
  343.     --nt
  344.     gen("END();")
  345.     gen("}") #end of function "program"
  346.     outfile = outfileB
  347.     gen("}")
  348.     outfile = outfileE
  349.     gen("}")
  350.     close(outfileF)
  351.     close(outfileB)
  352.     close(outfileE)
  353.     #emit BEGIN, END, user function definitions, globals
  354.     emit_functions() # to outfileC
  355.     emit_globalsEtc() #to outfileH
  356.     }
  357.  
  358. function boiler_plate()
  359.     {
  360. print "Entering"" boiler_plate"
  361.     #Note this comes after any opening comments in original
  362.     gen("/* " filename ".c */")
  363.     gen("#include \"" filename ".h\"")
  364.     gen("")
  365.     gen("RETTYPE program()\n\t{");
  366.     gen("\tinit_consts_and_vars();")
  367.     gen("\tBEGIN();")
  368.     gen("\twhile (getrec())\n\t\t{")
  369.     
  370.     outfile = outfileB
  371.     gen("RETTYPE BEGIN()\n\t{")
  372.     
  373.     outfile = outfileE
  374.     gen("RETTYPE END()\n\t{")
  375.     
  376.     outfile = outfileC
  377.     }
  378.  
  379. #start
  380. #    : {NEWLINE} rule {NEWLINE} {rule {NEWLINE}} 
  381. #    ;
  382. function start()
  383.     {
  384. print "Entering"" start"
  385.     #advance() - done before, to emit opening comments before boiler plate
  386.     newline()
  387.     rule()
  388.     newline()
  389.     while (toktype != EOF)
  390.         {
  391.         rule()
  392.         newline()
  393.         }
  394.     }
  395.  
  396. #rule
  397. #    : LEX_BEGIN action
  398. #    | LEX_END action
  399. #    | pattern action
  400. #    | action
  401. #    | pattern statement_term
  402. #    | function_prologue function_body
  403. #    ;
  404. function rule()
  405.     {
  406. print "Entering"" rule"
  407.     if (toktype == KEY && tok == "BEGIN")
  408.         {
  409.         outfile = outfileB
  410.         oldNT = nt
  411.         nt = 1
  412.         advance()
  413.         action()
  414.         outfile = outfileC
  415.         nt = oldNT
  416.         }
  417.     else if (toktype == KEY && tok == "END")
  418.         {
  419.         outfile = outfileE
  420.         oldNT = nt
  421.         nt = 1
  422.         advance()
  423.         action()
  424.         outfile = outfileC
  425.         nt = oldNT
  426.         }
  427.     else if (toktype == KEY && (tok == "function" || tok == "func"))
  428.         {
  429.         outfile = outfileF
  430.         oldNT = nt
  431.         nt = 0
  432.         function_prologue()
  433.         function_body()
  434.         empty_not_globals()
  435.         outfile = outfileC
  436.         nt = oldNT
  437.         }
  438.     else if (tok == "{")
  439.         {
  440.         action()
  441.         }
  442.     else if (toktype != EOF)
  443.         {
  444.         gen("if (" pattern() ")")
  445.         nt++
  446.         gen("{")
  447.         if (tok == "{")
  448.             {
  449.             action()
  450.             }
  451.         else #default is print $0
  452.             {
  453.             statement_term()
  454.             gen("print(field((AWKNUM)0));")
  455.             }
  456.         gen("}")
  457.         nt--
  458.         }
  459.     }
  460.  
  461. #func_name
  462. #    : NAME
  463. #    | FUNC_CALL
  464. #    ;
  465. function func_name(    name)
  466.     {
  467. print "Entering"" func_name"
  468.     if (toktype == NAME || toktype == FUNC_CALL)
  469.         {
  470.         name = tok "_u"
  471.         advance()
  472.         return name
  473.         }
  474.     else
  475.         error("Expected but did not find a function name")
  476.     }
  477.  
  478. #function_prologue
  479. #    : LEX_FUNCTION func_name "(" [param_list] ")" {NEWLINE}
  480. #    ;
  481. function function_prologue(        name)
  482.     {
  483. print "Entering"" function_prologue"
  484.     if (tok == "func")
  485.         eat("func")
  486.     else
  487.         eat("function")
  488.     name = func_name()
  489.     eat("(")
  490.     gen("RETTYPE " name "(" param_list() ")")
  491.     eat(")")
  492.     newline()
  493.     }
  494.  
  495. #function_body
  496. #    : "{" {NEWLINE} statements "}" {NEWLINE}
  497. #    ;
  498. function function_body()
  499.     {
  500. print "Entering"" function_body"
  501.     ++nt
  502.     eat("{")
  503.     gen("{")
  504.     newline()
  505.     statements()
  506.     eat("}")
  507.     gen("return( return_it(copy_to_temp(NULLNODE)) );") #just in case....
  508.     gen("}\n")
  509.     newline()
  510.     }
  511.  
  512. #pattern
  513. #    : exp0 ["," {NEWLINE} exp0]
  514. #    ;
  515. # from_to(int, val1, val2) returns "Bool", internally tracks
  516. #whether range has been activated - note returns "TRUE" for val2
  517. #and then deactivates. "ranger" is an index, use tbd
  518. function pattern(     e)
  519.     {
  520. print "Entering"" pattern"
  521.     e = exp0()
  522.     if (tok ==",") #range pattern, latch on/switch off
  523.         {
  524.         advance()
  525.         newline()
  526.         return "from_to(" ranger++ ", " e ", " exp0() ")"
  527.         }
  528.     else
  529.         return e
  530.     }
  531.  
  532. #regexp
  533. #     * In this rule, want_regexp tells yylex that the next thing
  534. #     * is a regexp so it should read up to the closing slash.
  535. #    : "/" REGEXP "/"
  536. #    ;
  537. # Note toktype is REGEXP, slashes not included
  538. function regexp(    r)
  539.     {
  540. print "Entering"" regexp"
  541.     if (tok == "/")
  542.         {
  543.         want_regexp = 1
  544.         advance()
  545.         want_regexp = 0
  546.         r = "SLSHREG, " "\"" tok "\""
  547.         advance()
  548.         if (r in const)
  549.             return "CONSTANT_NODE(" const[r] ")"
  550.         else
  551.             {
  552.             const[r] = num_constants
  553.             return "CONSTANT_NODE(" num_constants++ ")"
  554.             }
  555.         }
  556.     else
  557.         error("regular expression not terminated with \"/\"")
  558.     }
  559.  
  560. #action
  561. #    : "{" {NEWLINE} "}" {NEWLINE} [";"]
  562. #        <
  563. #            * empty actions are different from missing actions *
  564. #            $$ = node ((NODE *) NULL, Node_illegal, (NODE *) NULL);
  565. #        >
  566. #    | "{" {NEWLINE} statements "}" {NEWLINE} [";"]
  567. #    ;
  568. function action()
  569.     {
  570. print "Entering"" action"
  571.     eat("{")
  572.     newline()
  573.     if (tok == "}") #empty action
  574.         {
  575.         advance()
  576.         newline()
  577.         if (tok == ";")
  578.             advance()
  579.         gen("null_op();")
  580.         }
  581.     statements()
  582.     eat("}")
  583.     newline()
  584.     if (tok == ";")
  585.         advance()
  586.     }
  587.  
  588. #statements
  589. #    : statement {statement}
  590. #    ;
  591. function statements(    rsult)
  592.     {
  593. print "Entering"" statements"
  594.     statement()
  595.     while (first_of_statement())
  596.         statement()
  597.     }
  598.  
  599. #statement_term
  600. #    : NEWLINE {NEWLINE}
  601. #    | ";" {NEWLINE}
  602. #    ???| implied by "}"
  603. #    ;
  604. #Note statement_term is not optional when called for.
  605. function statement_term()
  606.     {
  607. print "Entering"" statement_term"
  608.     if (tok == ";")
  609.         {
  610.         advance()
  611.         newline()
  612.         }
  613.     else if (tok == "\n")
  614.         newline()
  615.     else if (tok == "}")
  616.         return
  617.     else
  618.         error("statement not terminated")
  619.     }
  620.  
  621. #statement
  622. #    : ";" {NEWLINE}
  623. #    | "{" {NEWLINE} "}" {NEWLINE}
  624. #    | "{" {NEWLINE} statements "}" {NEWLINE}
  625. #    | if_statement
  626. #    | LEX_WHILE "(" exp0 ")" {NEWLINE} statement
  627. #    | LEX_DO {NEWLINE} statement LEX_WHILE "(" exp0 ")" {NEWLINE}
  628. #    | LEX_FOR "(" NAME LEX_IN NAME ")" {NEWLINE} statement
  629. #    | LEX_FOR "(" [exp0] ";" [exp0] ";" [exp0] ")" {NEWLINE} statement
  630. #    | LEX_BREAK statement_term
  631. #    | LEX_CONTINUE statement_term
  632. #    | print "(" expression_list ")" output_redir statement_term
  633. #    | print opt_rexpression_list output_redir statement_term
  634. #    | LEX_NEXT statement_term
  635. #    | LEX_EXIT [exp0] statement_term
  636. #    | LEX_RETURN [exp0] statement_term
  637. #    | LEX_DELETE NAME "[" expression_list "]" statement_term
  638. #    | exp0 statement_term
  639. #    ;
  640. #This is the main code generating function
  641. #Note: output_redir() returns "to_stdout()" if there isn't one
  642. function statement(        e,f,g, add_curly)
  643.     {
  644. print "Entering"" statement"
  645.     if (tok == ";")
  646.         {
  647.         gen("CLEARTEMPSTACK();")
  648.         advance()
  649.         newline()
  650.         }
  651.     else if (tok == "{")
  652.         {
  653.         gen("{")
  654.         advance()
  655.         newline()
  656.         while (first_of_statement())
  657.             statement()
  658.         #TO DO -special emit if block was empty?
  659.         eat("}")
  660.         gen("}")
  661.         newline()
  662.         }
  663.     else if (tok == "if")
  664.         {
  665.         if_statement()
  666.         }
  667.     else if (tok == "while")
  668.         {
  669.         advance()
  670.         eat("(")
  671.         gen("while (" exp0() ")")
  672.         eat(")")
  673.         ++nt
  674.         newline()
  675.         if (tok != "{")
  676.             {
  677.             add_curly = 1
  678.             gen("{")
  679.             }
  680.         statement()
  681.         if (add_curly == 1)
  682.             gen("}")
  683.         --nt
  684.         }
  685.     else if (tok == "do")
  686.         {
  687.         advance()
  688.         newline()
  689.         gen("do")
  690.         ++nt
  691.         if (tok != "{")
  692.             {
  693.             add_curly = 1
  694.             gen("{")
  695.             }
  696.         statement()
  697.         if (add_curly == 1)
  698.             gen("}")
  699.         ++nt
  700.         eat("while")
  701.         eat("(")
  702.         gen("while (" exp0() ");")
  703.         eat(")")
  704.         newline()
  705.         --nt
  706.         --nt
  707.         }
  708.     else if (tok == "for")
  709.         {
  710.         advance()
  711.         eat("(")
  712.         if (toktype == NAME)
  713.             {
  714.             lex_next()
  715.             if (nextTok == "in")
  716.                 {
  717.                 #for (assign(NAME1, first_in(NAME2); *string_val(NAME1); 
  718.                 # assign(NAME1, next_in(NAME2))
  719.                 e = tok #first name
  720.                 if (!(e in hAWK_VAR))
  721.                     e = e "_u"
  722.                 record_if_global(e)
  723.                 advance() # to the "in"
  724.                 eat("in") #now tok = second name
  725.                 if (!(tok in hAWK_VAR))
  726.                     tok = tok "_u"
  727.                 record_if_global(tok)
  728.                 gen("for (assign(" e ", first_in(" tok "); *string_val( " e ");")
  729.                 gen("\t\tassign(" e ", next_in(" tok "))")
  730.                 advance() # ")"
  731.                 eat(")")
  732.                 ++nt
  733.                 newline()
  734.                 if (tok != "{")
  735.                     {
  736.                     add_curly = 1
  737.                     gen("{")
  738.                     }
  739.                 statement()
  740.                 if (add_curly == 1)
  741.                     gen("}")
  742.                 --nt
  743.                 }
  744.             else #plain for, starting with NAME
  745.                 {
  746.                 e = exp0()
  747.                 eat(";")
  748.                 if (tok != ";")
  749.                     f = exp0()
  750.                 eat(";")
  751.                 if (tok != ")")
  752.                     g = exp0()
  753.                 eat(")")
  754.                 gen("for(" e ";" f ";" g ")")
  755.                 ++nt
  756.                 newline()
  757.                 if (tok != "{")
  758.                     {
  759.                     add_curly = 1
  760.                     gen("{")
  761.                     }
  762.                 statement()
  763.                 if (add_curly == 1)
  764.                     gen("}")
  765.                 --nt
  766.                 }
  767.             }
  768.         else #plain for
  769.             {
  770.             if (tok != ";")
  771.                 e = exp0()
  772.             eat(";")
  773.             if (tok != ";")
  774.                 f = exp0()
  775.             eat(";")
  776.             if (tok != ")")
  777.                 g = exp0()
  778.             eat(")")
  779.             gen("for(" e ";" f ";" g ")")
  780.             ++nt
  781.             newline()
  782.             if (tok != "{")
  783.                 {
  784.                 add_curly = 1
  785.                 gen("{")
  786.                 }
  787.             statement()
  788.             if (add_curly == 1)
  789.                 gen("}")
  790.             --nt
  791.             }
  792.         }
  793.     else if (tok == "break")
  794.         {
  795.         gen("CLEARTEMPSTACK();")
  796.         advance()
  797.         gen("break;")
  798.         statement_term()
  799.         }
  800.     else if (tok == "continue")
  801.         {
  802.         gen("CLEARTEMPSTACK();")
  803.         advance()
  804.         gen("continue;")
  805.         statement_term()
  806.         }
  807.     else if (tok == "print")
  808.         {
  809.         gen("CLEARTEMPSTACK();")
  810.         advance()
  811.         if (tok == "(")
  812.             {
  813.             advance()
  814.             e = expression_list()
  815.             eat(")")
  816.             f = output_redir()
  817.             statement_term()
  818.             gen("do_print(" f ", " num_expressions ", " e ");")
  819.             }
  820.         else
  821.             {
  822.             e = opt_rexpression_list()
  823.             f = output_redir()
  824.             statement_term()
  825.             gen("do_print(" f ", " num_expressions ", " e ");")
  826.             }
  827.         }
  828.     else if (tok == "printf")
  829.         {
  830.         gen("CLEARTEMPSTACK();")
  831.         advance()
  832.         if (tok == "(")
  833.             {
  834.             advance()
  835.             e = expression_list()
  836.             eat(")")
  837.             f = output_redir()
  838.             statement_term()
  839.             gen("do_printf(" f ", " num_expressions ", " e ");")
  840.             }
  841.         else
  842.             {
  843.             e = opt_rexpression_list()
  844.             f = output_redir()
  845.             statement_term()
  846.             gen("do_printf(" f ", " num_expressions ", " e ");")
  847.             }
  848.         }
  849.     else if (tok == "next")
  850.         {
  851.         gen("CLEARTEMPSTACK();")
  852.         advance()
  853.         statement_term()
  854.         gen("do_next();")
  855.         }
  856.     else if (tok == "exit")
  857.         {
  858.         gen("CLEARTEMPSTACK();")
  859.         advance()
  860.         if (tok != "\n" && tok != ";")
  861.             exp0()
  862.         statement_term()
  863.         gen("do_exit();")
  864.         }
  865.     else if (tok == "return")
  866.         {
  867.         gen("CLEARTEMPSTACK();")
  868.         advance()
  869.         if (tok != "\n" && tok != ";")
  870.             {
  871.             e = exp0()
  872.             statement_term()
  873.             gen("return(return_it(" e "));")
  874.             }
  875.         else
  876.             {
  877.             statement_term()
  878.             gen("return( return_it(copy_to_temp(NULLNODE)) );")
  879.             }
  880.         }
  881.     else if (tok == "delete")
  882.         {
  883.         gen("CLEARTEMPSTACK();")
  884.         advance()
  885.         e = tok
  886.         if (toktype != NAME)
  887.             error("delete not followed by array name")
  888.         if (!(e in hAWK_VAR))
  889.             e = e "_u"
  890.         record_if_global(e)
  891.         advance()
  892.         eat("[")
  893.         f = expression_list()
  894.         eat("]")
  895.         statement_term()
  896.         gen("array_delete(" e ", array_index(" num_expressions ", " f "));")
  897.         }
  898.     
  899.     else
  900.         {
  901.         gen("CLEARTEMPSTACK();")
  902.         gen(exp0() ";")
  903.         statement_term()
  904.         }
  905.     }
  906.  
  907. #if_statement
  908. #    : LEX_IF "(" exp0 ")" {NEWLINE} statement [ LEX_ELSE {NEWLINE} statement ]
  909. #    ;
  910. function if_statement(    add_curly)
  911.     {
  912. print "Entering"" if_statement"
  913.     advance()
  914.     eat("(")
  915.     gen("if (" exp0() ")")
  916.     eat(")")
  917.     ++nt
  918.     newline()
  919.     if (tok != "{")
  920.         {
  921.         add_curly = 1
  922.         gen("{")
  923.         }
  924.     statement()
  925.     if (add_curly == 1)
  926.         gen("}")
  927.     --nt
  928.     if (tok == "else")
  929.         {
  930.         advance()
  931.         gen("else")
  932.         newline()
  933.         if (tok != "if")
  934.             {
  935.             ++nt
  936.             if (tok != "{")
  937.                 {
  938.                 add_curly = 1
  939.                 gen("{")
  940.                 }
  941.             statement()
  942.             if (add_curly == 1)
  943.                 gen("}")
  944.             --nt
  945.             }
  946.         else
  947.             statement()
  948.         }
  949.     }
  950.  
  951. #input_redir
  952. #    : * empty *
  953. #    | "<" simp_exp
  954. #    ;
  955. function input_redir()
  956.     {
  957. print "Entering"" input_redir"
  958.     if (tok != "<")
  959.         return "from_stdin()"
  960.     else
  961.         {
  962.         advance()
  963.         return "from_file(" simp_exp() ")"
  964.         }
  965.     }
  966.  
  967. #output_redir
  968. #    : { (">" | ">>") exp0 }
  969. #    ;
  970. function output_redir()
  971.     {
  972. print "Entering"" output_redir"
  973.     if (toktype == ">" || toktype == APPEND_OP)
  974.         {
  975.         advance()
  976.         if (toktype == ">")
  977.             return "redirect(" exp0() ")"
  978.         else
  979.             return "redirect_append(" exp0() ")"
  980.         }
  981.     else
  982.         return "to_stdout()"
  983.     }
  984.  
  985. #param_list
  986. #    : NAME { "," {NEWLINE} NAME }
  987. #    ;
  988. # Note at this stage just the raw list of names, without
  989. # even commas, is created. When function is copied from
  990. # outfileF to outfileC then the proper declarations and commas
  991. # are issued.
  992. function param_list(    parms)
  993.     {
  994. print "Entering"" param_list"
  995.     if (tok == ")")
  996.         return ""
  997.     if (toktype != NAME)
  998.         error("Name is missing from function parameters")
  999.     if (!(tok in hAWK_VAR))
  1000.         tok = tok "_u"
  1001.     parms = tok
  1002.     record_not_global(tok)
  1003.     advance()
  1004.     if (tok == ")")
  1005.         return parms
  1006.     else
  1007.         {
  1008.         eat(",")
  1009.         newline()
  1010.         }
  1011.     while (tok != ")")
  1012.         {
  1013.         if (toktype != NAME)
  1014.             error("Name is missing from function parameters")
  1015.         if (!(tok in hAWK_VAR))
  1016.             tok = tok "_u"
  1017.         parms = parms " " tok
  1018.         record_not_global(tok)
  1019.         advance()
  1020.         if (tok == ",")
  1021.             {
  1022.             eat(",")
  1023.             newline()
  1024.             }
  1025.         }
  1026.     return parms
  1027.     }
  1028.  
  1029. # LA is tok != ">"|">>"|"<"|";"|"\n"
  1030. #opt_rexpression_list
  1031. #        : <loosePrint = 1>
  1032. #          [ exp0 { "," {NEWLINE} exp0 } ]
  1033. #          <loosePrint = 0>
  1034. #        ;
  1035. #Called only for print, so returns $0 if list is empty
  1036. function opt_rexpression_list(    e)
  1037.     {
  1038. print "Entering"" opt_rexpression_list"
  1039.     num_expressions = 1
  1040.     if (!(toktype in follow_opt_r_list))
  1041.         {
  1042.         loosePrint = 1
  1043.         e = exp0()
  1044.         while (tok == ",")
  1045.             {
  1046.             eat(",")
  1047.             newline()
  1048.             e = e ", " exp0()
  1049.             ++num_expressions
  1050.             }
  1051.         loosePrint = 0
  1052.         }
  1053.     else
  1054.         e = "field((AWKNUM)0)"
  1055.     return e
  1056.     }
  1057.  
  1058. # LA is tok != ")" only 
  1059. #opt_expression_list
  1060. #    : [ expression_list ]
  1061. #    ;
  1062. function opt_expression_list()
  1063.     {
  1064. print "Entering"" opt_expression_list"
  1065.     if (tok != ")")
  1066.         return expression_list()
  1067.     else
  1068.         {
  1069.         num_expressions = 0
  1070.         return ""
  1071.         }
  1072.     }
  1073.  
  1074. #expression_list
  1075. #    : exp0 { "," {NEWLINE} exp0 }
  1076. #    ;
  1077. function expression_list(    e)
  1078.     {
  1079. print "Entering"" expression_list"
  1080.     e = exp0()
  1081.     num_expressions = 1
  1082.     while (tok == ",")
  1083.         {
  1084.         advance()
  1085.         newline()
  1086.         e = e ", " exp0()
  1087.         ++num_expressions
  1088.         }
  1089.     return  e
  1090.     }
  1091.  
  1092. #exp0    : variable ASSIGNOP exp0
  1093. #        | exp1
  1094. #        ;
  1095. function exp0(        e,f)
  1096.     {
  1097. print "Entering"" exp0"
  1098.     e = exp1()
  1099.     if (toktype == ASSIGNOP || toktype == "=")
  1100.         {
  1101.         #Technically should check that e can be assigned to.
  1102.         f = tok
  1103.         advance()
  1104.         return op_table[f] e ", " exp0() ")"
  1105.         }
  1106.     else
  1107.         return e
  1108.     }
  1109.  
  1110. #exp1    : exp2 {"?" exp2 ":" exp2 }
  1111. function exp1(        e)
  1112.     {
  1113.     print "Entering"" exp1"
  1114.     e = exp2()
  1115.     if (tok == "?")
  1116.         {
  1117.         advance()
  1118.         return "T_F(" e ") ? " exp1()
  1119.         }
  1120.     else if (tok == ":")
  1121.         {
  1122.         advance()
  1123.         return e ":" exp1()
  1124.         }
  1125.     else
  1126.         return e
  1127.     }
  1128.  
  1129. #exp2    : exp3 { "||" exp3 }
  1130. #        ;
  1131. function exp2(        e)
  1132.     {
  1133. print "Entering"" exp2"
  1134.     e = exp3()
  1135.     if (toktype == LEX_OR)###
  1136.         e = "T_F(" e ")"###
  1137.     while (toktype == LEX_OR)
  1138.         {
  1139.         advance()
  1140.         e = e " || T_F(" exp3() ")"###
  1141.         ##e = "op_or(" exp3() ", " e ")"
  1142.         }
  1143.     return e
  1144.     }
  1145.  
  1146. #exp3    : exp4 { "&&" exp4 }
  1147. #        ;
  1148. function exp3(        e)
  1149.     {
  1150. print "Entering"" exp3"
  1151.     e = exp4()
  1152.     if (toktype == LEX_AND)###
  1153.         e = "T_F(" e ")"###
  1154.     while (toktype == LEX_AND)
  1155.         {
  1156.         advance()
  1157.         e = e " && T_F(" exp4() ")"###
  1158.         ##e = "op_and(" exp4() ", " e ")"
  1159.         }
  1160.     return e
  1161.     }
  1162.  
  1163. #exp4    : exp5 [LEX_IN NAME]
  1164. #        ;
  1165. #first for input_redir is "<" or zip - note it returns
  1166. # from_stdin() if no redirect.
  1167. #first for var is NAME or "$" (note it's optional)
  1168. function exp4(        e,f)
  1169.     {
  1170. print "Entering"" exp4"
  1171.     e = exp5()
  1172.     if (tok == "in")
  1173.         {
  1174.         advance()
  1175.         if (toktype != NAME)
  1176.             error("No array name following \"in\" operator")
  1177.         f = tok
  1178.         if (!(f in hAWK_VAR))
  1179.             f = f "_u"
  1180.         record_if_global(f)
  1181.         advance()
  1182.         return "in(" e ", " f ")"
  1183.         }
  1184.     return e
  1185.     }
  1186.  
  1187. #exp5    : exp6 { MATCHOP exp6 }
  1188. #        ;
  1189. function exp5(        e, f)
  1190.     {
  1191. print "Entering"" exp5"
  1192.     e = exp6()
  1193.     while (toktype == MATCHOP || tok == "~")
  1194.         {
  1195.         f = tok
  1196.         advance()
  1197.         e = op_table[f] exp6() ", " e ")"
  1198.         }
  1199.     return e
  1200.     }
  1201.  
  1202. # do ">"|"<" only if !loosePrint
  1203. #exp6    : exp7 { (RELOP|">"|"<") exp7 }
  1204. #        ;
  1205. function exp6(        e, f)
  1206.     {
  1207. print "Entering"" exp6"
  1208.     e = exp7()
  1209.     while (toktype == RELOP || toktype == "<" ||
  1210.         (!loosePrint && (toktype == ">")))
  1211.         {
  1212.         f = tok
  1213.         advance()
  1214.         e = op_table[f] exp7() ", " e ")"
  1215.         }
  1216.     return e
  1217.     }
  1218.  
  1219. #exp7    : exp8 { exp8 } - implied CONCAT_OP
  1220. #        ;
  1221. function exp7(    e)
  1222.     {
  1223. print "Entering"" exp7"
  1224.     e = exp8();
  1225.     while (!(toktype in follow_exp8))
  1226.         e = "concat(" exp8() ", " e ")"
  1227.     return e
  1228.     }
  1229.  
  1230. #exp8    : exp9 { ("+"|"-") exp9 }
  1231. #        ;
  1232. function exp8(        e,f)
  1233.     {
  1234. print "Entering"" exp8"
  1235.     e = exp9()
  1236.     while (tok == "+" || tok == "-")
  1237.         {
  1238.         f = tok
  1239.         advance()
  1240.         e = op_table[f] exp9() ", " e ")"
  1241.         }
  1242.     return e
  1243.     }
  1244.  
  1245. #exp9    : exp10 { ("*"|"/"|"%") exp10 }
  1246. #        ;
  1247. function exp9(        e, f)
  1248.     {
  1249. print "Entering"" exp9"
  1250.     e = exp10()
  1251.     while (tok == "*" || tok == "/" || tok == "%")
  1252.         {
  1253.         f = tok
  1254.         advance()
  1255.         e = op_table[f] exp10() ", " e ")"
  1256.         }
  1257.     return e
  1258.     }
  1259.  
  1260. #exp10    : "!" ( regexp | exp11 )
  1261. #        | [("+"|"-")] exp11
  1262. #        ;
  1263. function exp10(        re)
  1264.     {
  1265. print "Entering"" exp10"
  1266.     if (tok == "!")
  1267.         {
  1268.         eat("!")
  1269.         if (tok == "/")
  1270.             {
  1271.             re = "string_to_regex(" regexp() ")"
  1272.             }
  1273.         else
  1274.             re = exp11()
  1275.         return "op_not(" re ")"
  1276.         }
  1277.     else
  1278.         {
  1279.         if (tok == "+" || tok == "-")
  1280.             {
  1281.             if (tok == "-")
  1282.                 {
  1283.                 advance()
  1284.                 return "op_negate(" exp11() ")"
  1285.                 }
  1286.             else
  1287.                 {
  1288.                 advance()
  1289.                 return exp11()
  1290.                 }
  1291.             }
  1292.         else
  1293.             return exp11()
  1294.         }
  1295.     }
  1296.  
  1297. #exp11    : exp12 { "^" exp12 }
  1298. #        ;
  1299. #Note exponentiation is right-associative, the recursive call
  1300. #to exp11 is not a typo.
  1301. function exp11(        e)
  1302.     {
  1303. print "Entering"" exp11"
  1304.     e = exp12()
  1305.     if (tok == "^")
  1306.         {
  1307.         advance()
  1308.         return "op_exp(" e ", " exp11() ")"
  1309.         }
  1310.     else
  1311.         return e
  1312.     }
  1313.  
  1314. #exp12    : YSTRING | NUMBER
  1315. #        | regexp
  1316. #        |GETLINE [variable] [input_redir]
  1317. #        | LEX_BUILTIN "(" opt_expression_list ")"
  1318. #        | LEX_LENGTH "(" opt_expression_list ")"
  1319. #        | LEX_LENGTH
  1320. #        | FUNC_CALL "(" opt_expression_list ")"
  1321. #        | [("++"|"--")] variable
  1322. #        | variable ("++"|"--")
  1323. #        | "(" exp0 ( ")" |
  1324. #            "," {NEWLINE} exp0
  1325. #            { "," {NEWLINE} exp0 }
  1326. #             ")" LEX_IN NAME )
  1327. #        ;
  1328. function exp12(        e,f)
  1329.     {
  1330. print "Entering"" exp12"
  1331.     if (tok == "/")
  1332.         {
  1333.         return regexp()
  1334.         }
  1335.     else if (toktype == YSTRING)
  1336.         {
  1337.         e = "STRING, " tok
  1338.         advance()
  1339.         if (e in const)
  1340.             return "CONSTANT_NODE(" const[e] ")"
  1341.         else
  1342.             {
  1343.             const[e] = num_constants
  1344.             return "CONSTANT_NODE(" num_constants++ ")"
  1345.             }
  1346.         }
  1347.     else if (toktype == NUMBER)
  1348.         {
  1349.         e = "DOUBLE, \"" tok "\"" #for init_consts_and_vars()
  1350.         advance()
  1351.         if (e in const)
  1352.             return "CONSTANT_NODE(" const[e] ")"
  1353.         else
  1354.             {
  1355.             const[e] = num_constants
  1356.             return "CONSTANT_NODE(" num_constants++ ")"
  1357.             }
  1358.         }
  1359.     else if (toktype == LEX_GETLINE)
  1360.         {
  1361.         advance()
  1362.         if (toktype == NAME || tok == "$")
  1363.             e = variable()
  1364.         else
  1365.             e = "NULL"
  1366.         return "get_line(" e ", " input_redir() ")"
  1367.         }
  1368.     else if (toktype == LEX_BUILTIN)
  1369.         {
  1370.         f = hAWK_BUILTIN[tok]
  1371.         advance()
  1372.         eat("(")
  1373.         e = opt_expression_list()
  1374.         eat(")")
  1375.         return f"(" e ")"
  1376.         }
  1377.     else if (toktype == LEX_LENGTH)
  1378.         {
  1379.         f = hAWK_LENGTH[tok]
  1380.         advance()
  1381.         if (tok != "(")
  1382.             return f "(field((AWKNUM)0))"
  1383.         else
  1384.             {
  1385.             eat("(")
  1386.             e = opt_expression_list()
  1387.             eat(")")
  1388.             return f"(" e ")"
  1389.             }
  1390.         }
  1391.     else if (toktype == FUNC_CALL)
  1392.         {
  1393.         f = tok "_u"
  1394.         advance()
  1395.         eat("(")
  1396.         e = opt_expression_list()
  1397.         #max number of args in a function call determines split
  1398.         #between parameters and local variables
  1399.         if (num_expressions > maxparms[f]+0)
  1400.             maxparms[f] = num_expressions
  1401.         eat(")")
  1402.         return f "(" e ")"
  1403.         }
  1404.     else if (tok == "(")
  1405.         {
  1406.         advance()
  1407.         e = exp0()
  1408.         if (tok == ")")
  1409.             {
  1410.             advance()
  1411.             if (tok != "in")
  1412.                 return e
  1413.             else
  1414.                 {
  1415.                 advance()
  1416.                 if (toktype != NAME)
  1417.                     error("No array name following \"in\" operator")
  1418.                 f = tok
  1419.                 if (!(f in hAWK_VAR))
  1420.                     f = f "_u"
  1421.                 record_if_global(f)
  1422.                 advance()
  1423.                 return "in(array_index(1, " e "), " f ")"
  1424.                 }
  1425.             }
  1426.         else
  1427.             {
  1428.             num_expressions = 1
  1429.             while (tok != ")")
  1430.                 {
  1431.                 eat(",")
  1432.                 newline()
  1433.                 e = e "," exp0()
  1434.                 ++num_expressions
  1435.                 }
  1436.             advance()
  1437.             eat("in")
  1438.             if (toktype != NAME)
  1439.                 error("No array name following \"in\" operator")
  1440.             f = tok
  1441.             if (!(f in hAWK_VAR))
  1442.                 f = f "_u"
  1443.             record_if_global(f)
  1444.             advance()
  1445.             return "in(array_index(num_expressions, " e "), " f ")"
  1446.             }
  1447.         }
  1448.     else if (tok == "++" || tok == "--")
  1449.         {
  1450.         f = tok
  1451.         advance()
  1452.         if (f == "++")
  1453.             return "op_preinc(" variable() ")"
  1454.         else
  1455.             return "op_predec(" variable() ")"
  1456.         }
  1457.     else #gotta be a variable
  1458.         {
  1459.         e = variable()
  1460.         if (tok == "++" || tok == "--")
  1461.             {
  1462.             f = tok
  1463.             advance()
  1464.             if (f == "++")
  1465.                 return "op_postinc(" e ")"
  1466.             else
  1467.                 return "op_postdec(" e ")"
  1468.             }
  1469.         else
  1470.             return e
  1471.         }
  1472.     }
  1473.  
  1474. #simp_exp: sexp9 { ("+"|"-") sexp9 }
  1475. #        ;
  1476. function simp_exp(        e,f)
  1477.     {
  1478. print "Entering"" simp_exp"
  1479.     e = sexp9()
  1480.     while (tok == "+" || tok == "-")
  1481.         {
  1482.         f = tok
  1483.         advance()
  1484.         e = op_table[f] sexp9() ", " e ")"
  1485.         }
  1486.     return e
  1487.     }
  1488.  
  1489. #sexp9    : sexp10 { ("*"|"/"|"%") sexp10 }
  1490. #        ;
  1491. function sexp9(        e,f)
  1492.     {
  1493. print "Entering"" sexp9"
  1494.     e = sexp10()
  1495.     while (tok == "*" || tok == "/" || tok == "%")
  1496.         {
  1497.         f = tok
  1498.         advance()
  1499.         e = op_table[f] sexp10() ", " e ")"
  1500.         }
  1501.     return e
  1502.     }
  1503.  
  1504. #sexp10    : ["!"|"+"|"-"] sexp11
  1505. #        ;
  1506. function sexp10()
  1507.     {
  1508. print "Entering"" sexp10"
  1509.     if (tok == "!")
  1510.         {
  1511.         eat("!")
  1512.         return "op_not(" sexp11() ")"
  1513.         }
  1514.     else
  1515.         {
  1516.         if (tok == "+" || tok == "-")
  1517.             {
  1518.             if (tok == "-")
  1519.                 {
  1520.                 advance()
  1521.                 return "op_negate(" sexp11() ")"
  1522.                 }
  1523.             else
  1524.                 {
  1525.                 advance()
  1526.                 return sexp11()
  1527.                 }
  1528.             }
  1529.         else
  1530.             return sexp11()
  1531.         }
  1532.     }
  1533.  
  1534. #sexp11    : sexp12 { "^" sexp12 }
  1535. #        ;
  1536. #Note exponentiation is right-associative, the recursive call
  1537. #to sexp11 is not a typo.
  1538. function sexp11(        e)
  1539.     {
  1540. print "Entering"" sexp11"
  1541.     e = sexp12()
  1542.     if (tok == "^")
  1543.         {
  1544.         advance()
  1545.         return "op_exp(" e ", " sexp11() ")"
  1546.         }
  1547.     else
  1548.         return e
  1549.     }
  1550.  
  1551. #sexp12    : YSTRING | NUMBER
  1552. #        | LEX_BUILTIN "(" opt_expression_list ")"
  1553. #        | LEX_LENGTH "(" opt_expression_list ")"
  1554. #        | LEX_LENGTH
  1555. #        | FUNC_CALL "(" opt_expression_list ")"
  1556. #        | [("++"|"--")] variable
  1557. #        | variable ("++"|"--")
  1558. #        | "(" exp0 ")"
  1559. #        ;
  1560. function sexp12(        e,f)
  1561.     {
  1562. print "Entering"" sexp12"
  1563.     if (toktype == YSTRING)
  1564.         {
  1565.         e = "STRING, " tok
  1566.         advance()
  1567.         if (e in const)
  1568.             return "CONSTANT_NODE(" const[e] ")"
  1569.         else
  1570.             {
  1571.             const[e] = num_constants
  1572.             return "CONSTANT_NODE(" num_constants++ ")"
  1573.             }
  1574.         }
  1575.     else if (toktype == NUMBER)
  1576.         {
  1577.         e = "DOUBLE, \"" tok "\"" #for init_consts_and_vars()
  1578.         advance()
  1579.         if (e in const)
  1580.             return "CONSTANT_NODE(" const[e] ")"
  1581.         else
  1582.             {
  1583.             const[e] = num_constants
  1584.             return "CONSTANT_NODE(" num_constants++ ")"
  1585.             }
  1586.         }
  1587.     else if (toktype == LEX_BUILTIN)
  1588.         {
  1589.         f = hAWK_BUILTIN[tok]
  1590.         advance()
  1591.         eat("(")
  1592.         e = opt_expression_list()
  1593.         eat(")")
  1594.         return f"(" e ")"
  1595.         }
  1596.     else if (toktype == LEX_LENGTH)
  1597.         {
  1598.         f = hAWK_LENGTH[tok]
  1599.         advance()
  1600.         if (tok != "(")
  1601.             return f "(field((AWKNUM)0))"
  1602.         else
  1603.             {
  1604.             eat("(")
  1605.             e = opt_expression_list()
  1606.             eat(")")
  1607.             return f"(" e ")"
  1608.             }
  1609.         }
  1610.     else if (toktype == FUNC_CALL)
  1611.         {
  1612.         f = tok "_u"
  1613.         advance()
  1614.         eat("(")
  1615.         e = opt_expression_list()
  1616.         #max number of args in a function call determines split
  1617.         #between parameters and local variables
  1618.         if (num_expressions > maxparms[f]+0)
  1619.             maxparms[f] = num_expressions
  1620.         eat(")")
  1621.         return f "(" e ")"
  1622.         }
  1623.     else if (tok == "(")
  1624.         {
  1625.         advance()
  1626.         e = exp0()
  1627.         eat(")")
  1628.         return e
  1629.         }
  1630.     else if (tok == "++" || tok == "--")
  1631.         {
  1632.         f = tok
  1633.         advance()
  1634.         if (f == "++")
  1635.             return "op_preinc(" variable() ")"
  1636.         else
  1637.             return "op_predec(" variable() ")"
  1638.         }
  1639.     else #gotta be a variable
  1640.         {
  1641.         e = variable()
  1642.         if (tok == "++" || tok == "--")
  1643.             {
  1644.             f = tok
  1645.             advance()
  1646.             if (f == "++")
  1647.                 return "op_postinc(" e ")"
  1648.             else
  1649.                 return "op_postdec(" e ")"
  1650.             }
  1651.         else
  1652.             return e
  1653.         }
  1654.     }
  1655.  
  1656. #variable
  1657. #    : NAME
  1658. #    | NAME "[" expression_list "]"
  1659. #    | "$" simp_exp
  1660. #    ;
  1661. function variable(        id, se)
  1662.     {
  1663. print "Entering"" variable"
  1664.     if (toktype == NAME)
  1665.         {
  1666.         if (!(tok in hAWK_VAR))
  1667.             tok = tok "_u"
  1668.         record_if_global(tok)
  1669.         id = tok
  1670.         advance()
  1671.         if (tok == "[")
  1672.             {
  1673.             advance()
  1674.             se = expression_list()
  1675.             eat("]")
  1676.             return "array(" id ", array_index(" num_expressions ", " se "))"
  1677.             return "array(" id ", " se ")"
  1678.             }
  1679.         else
  1680.             return id
  1681.         }
  1682.     else if (tok == "$")
  1683.         {
  1684.         advance()
  1685.         return "field(" simp_exp() ")"
  1686.         }
  1687.     else
  1688.         error("expected variable or constant")
  1689.     }
  1690.  
  1691. # 37 ways to name your token
  1692. function init_toktypes()
  1693.     {
  1694. print "Entering"" init_toktypes"
  1695.     FUNC_CALL = 258
  1696.     NAME = 259
  1697.     REGEXP = 260
  1698.     ERROR = 261
  1699.     NUMBER = 262
  1700.     YSTRING = 263
  1701.     RELOP = 264
  1702.     APPEND_OP = 265
  1703.     ASSIGNOP = 266
  1704.     MATCHOP = 267
  1705.     NEWLINE = 268
  1706.     CONCAT_OP = 269
  1707.     LEX_BEGIN = 270
  1708.     LEX_END = 271
  1709.     LEX_IF = 272
  1710.     LEX_ELSE = 273
  1711.     LEX_RETURN = 274
  1712.     LEX_DELETE = 275
  1713.     LEX_WHILE = 276
  1714.     LEX_DO = 277
  1715.     LEX_FOR = 278
  1716.     LEX_BREAK = 279
  1717.     LEX_CONTINUE = 280
  1718.     LEX_PRINT = 281
  1719.     LEX_PRINTF = 282
  1720.     LEX_NEXT = 283
  1721.     LEX_EXIT = 284
  1722.     LEX_FUNCTION = 285
  1723.     LEX_GETLINE = 286
  1724.     LEX_IN = 287
  1725.     LEX_AND = 288
  1726.     LEX_OR = 289
  1727.     INCREMENT = 290
  1728.     DECREMENT = 291
  1729.     LEX_BUILTIN = 292
  1730.     LEX_LENGTH = 293
  1731.     UNARY = 294
  1732.     KEY = 295
  1733.     EOF = 296
  1734.     }
  1735.  
  1736. # hAWK_BUILTIN, hAWK_LENGTH, hAWK_KEY arrays (tables)
  1737. function init_tables()
  1738.     {
  1739. print "Entering"" init_tables"
  1740.     hAWK_BUILTIN["atan2"] = "fn_atan2"
  1741.     hAWK_BUILTIN["close"] = "fn_close"
  1742.     hAWK_BUILTIN["cos"] = "fn_cos"
  1743.     hAWK_BUILTIN["exp"] = "fn_exp"
  1744.     hAWK_BUILTIN["gsub"] = "fn_gsub"
  1745.     hAWK_BUILTIN["hAWK"] = "fn_hAWK"
  1746.     hAWK_BUILTIN["index"] = "fn_index"
  1747.     hAWK_BUILTIN["int"] = "fn_int"
  1748.     hAWK_BUILTIN["log"] = "fn_log"
  1749.     hAWK_BUILTIN["match"] = "fn_match"
  1750.     hAWK_BUILTIN["progress"] = "fn_progress"
  1751.     hAWK_BUILTIN["prompt"] = "fn_prompt"
  1752.     hAWK_BUILTIN["rand"] = "fn_rand"
  1753.     hAWK_BUILTIN["sin"] = "fn_sin"
  1754.     hAWK_BUILTIN["sort"] = "fn_sort"
  1755.     hAWK_BUILTIN["split"] = "fn_split"
  1756.     hAWK_BUILTIN["sprintf"] = "fn_sprintf"
  1757.     hAWK_BUILTIN["sqrt"] = "fn_sqrt"
  1758.     hAWK_BUILTIN["srand"] = "fn_srand"
  1759.     hAWK_BUILTIN["sub"] = "fn_sub"
  1760.     hAWK_BUILTIN["substr"] = "fn_substr"
  1761.     hAWK_BUILTIN["system"] = "fn_system"
  1762.     hAWK_BUILTIN["time"] = "fn_time"
  1763.     hAWK_BUILTIN["tolower"] = "fn_tolower"
  1764.     hAWK_BUILTIN["toupper"] = "fn_toupper"
  1765.     
  1766.     hAWK_LENGTH["length"] = "fn_length"
  1767.     hAWK_LENGTH["lookup"] = "fn_lookup"
  1768.     
  1769.     hAWK_KEY["BEGIN"] = 1
  1770.     hAWK_KEY["END"] = 1
  1771.     hAWK_KEY["break"] = 1
  1772.     hAWK_KEY["continue"] = 1
  1773.     hAWK_KEY["delete"] = 1
  1774.     hAWK_KEY["do"] = 1
  1775.     hAWK_KEY["else"] = 1
  1776.     hAWK_KEY["exit"] = 1
  1777.     hAWK_KEY["for"] = 1
  1778.     hAWK_KEY["func"] = 1
  1779.     hAWK_KEY["function"] = 1
  1780.     hAWK_KEY["getline"] = 1
  1781.     hAWK_KEY["if"] = 1
  1782.     hAWK_KEY["in"] = 1
  1783.     hAWK_KEY["next"] = 1
  1784.     hAWK_KEY["print"] = 1
  1785.     hAWK_KEY["printf"] = 1
  1786.     hAWK_KEY["return"] = 1
  1787.     hAWK_KEY["while"] = 1
  1788.     
  1789.     # builtin variables
  1790.     hAWK_VAR["ARGC"] = 1
  1791.     hAWK_VAR["ARGV"] = 1
  1792.     hAWK_VAR["FILENAME"] = 1
  1793.     hAWK_VAR["FNR"] = 1
  1794.     hAWK_VAR["FS"] = 1
  1795.     hAWK_VAR["IGNORECASE"] = 1
  1796.     hAWK_VAR["NF"] = 1
  1797.     hAWK_VAR["NR"] = 1
  1798.     hAWK_VAR["OFMT"] = 1
  1799.     hAWK_VAR["OFS"] = 1
  1800.     hAWK_VAR["ORS"] = 1
  1801.     hAWK_VAR["RS"] = 1
  1802.     hAWK_VAR["RSTART"] = 1
  1803.     hAWK_VAR["RLENGTH"] = 1
  1804.     hAWK_VAR["SUBSEP"] = 1
  1805.     hAWK_VAR["RUNERR"] = 1
  1806.     hAWK_VAR["STDPATH"] = 1
  1807.     hAWK_VAR["TIME"] = 1
  1808.  
  1809.     #table of function names, implementing operators
  1810.     #Not in the table; || && getline in funccall redirection
  1811.     #    unary +/- ++ -- $ ()
  1812.     op_table["="] = "op_assign("
  1813.     op_table["+="] = "op_plus_equals("
  1814.     op_table["-="] = "op_minus_equals("
  1815.     op_table["*="] = "op_times_equals("
  1816.     op_table["/="] = "op_div_equals("
  1817.     op_table["%="] = "op_mod_equals("
  1818.     op_table["^="] = "op_exp_equals("
  1819.     op_table["~"] = "op_match("
  1820.     op_table["!~"] = "op_not_match("
  1821.     op_table["<"] = "op_lt("
  1822.     op_table["<="] = "op_le("
  1823.     op_table[">"] = "op_gt("
  1824.     op_table[">="] = "op_ge("
  1825.     op_table["=="] = "op_equiv("
  1826.     op_table["!="] = "op_not_equiv("
  1827.     op_table["+"] = "op_plus("
  1828.     op_table["-"] = "op_minus("
  1829.     op_table["*"] = "op_times("
  1830.     op_table["/"] = "op_div("
  1831.     op_table["%"] = "op_mod("
  1832.     op_table["!"] = "op_not("
  1833.     op_table["^"] = "op_exp("
  1834.     
  1835.     #first and follow sets
  1836.     #follow_exp8 is used to tell if concatenation is needed
  1837.     follow_exp8["="] = 1
  1838.     follow_exp8[ASSIGNOP] = 1
  1839.     follow_exp8["?"] = 1
  1840.     follow_exp8[":"] = 1
  1841.     follow_exp8[LEX_OR] = 1
  1842.     follow_exp8[LEX_AND] = 1
  1843.     follow_exp8[KEY] = 1
  1844.     follow_exp8[EOF] = 1
  1845.     follow_exp8[MATCHOP] = 1
  1846.     follow_exp8[RELOP] = 1
  1847.     follow_exp8["~"] = 1
  1848.     follow_exp8["<"] = 1
  1849.     follow_exp8[">"] = 1
  1850.     follow_exp8[","] = 1
  1851.     follow_exp8[";"] = 1
  1852.     follow_exp8["}"] = 1
  1853.     follow_exp8["{"] = 1
  1854.     follow_exp8[")"] = 1
  1855.     follow_exp8["]"] = 1
  1856.     follow_exp8[NEWLINE] = 1
  1857.     
  1858.     follow_opt_r_list[">"] = 1
  1859.     follow_opt_r_list[APPEND_OP] = 1
  1860.     follow_opt_r_list["<"] = 1
  1861.     follow_opt_r_list[";"] = 1
  1862.     follow_opt_r_list[NEWLINE] = 1
  1863.     
  1864.     first_statement[";"] = 1
  1865.     first_statement["{"] = 1
  1866.     first_statement["("] = 1
  1867.     first_statement[KEY] = 1 #NOTE except BEGIN, END, else, in, func(tion)
  1868.     first_statement[LEX_PRINT] = 1
  1869.     first_statement[LEX_PRINTF] = 1
  1870.     first_statement["/"] = 1
  1871.     first_statement[NAME] = 1
  1872.     first_statement["$"] = 1
  1873.     first_statement[LEX_BUILTIN] = 1
  1874.     first_statement[LEX_LENGTH] = 1
  1875.     first_statement[FUNC_CALL] = 1
  1876.     first_statement[YSTRING] = 1
  1877.     first_statement[NUMBER] = 1
  1878.     first_statement["!"] = 1
  1879.     first_statement["+"] = 1
  1880.     first_statement["-"] = 1
  1881.     first_statement[INCREMENT] = 1
  1882.     first_statement[DECREMENT] = 1
  1883.     
  1884.     bad_first_stat_key["BEGIN"] = 1
  1885.     bad_first_stat_key["END"] = 1
  1886.     bad_first_stat_key["else"] = 1
  1887.     bad_first_stat_key["in"] = 1
  1888.     bad_first_stat_key["func"] = 1
  1889.     bad_first_stat_key["function"] = 1
  1890.     }
  1891.  
  1892. function first_of_statement()
  1893.     {
  1894. print "Entering"" first_of_statement"
  1895.     if (toktype in first_statement)
  1896.         {
  1897.         if (toktype != KEY)
  1898.             return 1
  1899.         if (tok in bad_first_stat_key)
  1900.             return 0
  1901.         return 1
  1902.         }
  1903.     else
  1904.         return 0
  1905.     }
  1906.  
  1907. function record_not_global(n)
  1908.     {
  1909. print "Entering"" record_not_global"
  1910.     not_global[n] = 1
  1911.     }
  1912. function empty_not_globals(        i)
  1913.     {
  1914. print "Entering"" empty_not_globals"
  1915.     for (i in not_global)
  1916.         delete not_global[i]
  1917.     }
  1918.  
  1919. function record_if_global(n)
  1920.     {
  1921. print "Entering"" record_if_global"
  1922.     if (!(n in not_global) &&
  1923.         !(n in hAWK_VAR) &&
  1924.         !(n in globals))
  1925.         globals[n] = 1
  1926.     }
  1927.  
  1928. ############## ##############
  1929. #Create init_consts_and_vars to outfileC
  1930. #Copy outfileB (BEGIN) and outfileE (END) to outfileC verbatim.
  1931. #Copy outfileF to end of outfileC - includes
  1932. #definitions for all user functions. Adjust declarations
  1933. #and prototypes to move local decls inside function body.
  1934. #Note in outfileF the parms are just a raw space-separated list
  1935. #with no type or commas, good format for split()
  1936. function emit_functions(    i,n,m,p,loc,t,q,k)
  1937.     {
  1938. print "Entering"" emit_functions"
  1939.     print "void init_consts_and_vars()\n\t{"  > outfileC
  1940.     for (i in const)
  1941.         print "\tinit_constant_node(" const[i] ", " i ");" > outfileC
  1942.     gMax = sort(globals, gIndex, "d")
  1943.     if (gMax > 0)
  1944.         {
  1945.         print "/* globals */" > outfileC
  1946.         for (i = 1; i <= gMax; ++i)
  1947.             print "\tinit_var(" gIndex[i] ", NULLNODE);" > outfileC
  1948.         }
  1949.     print "\t}\n"  > outfileC
  1950.     while (getline < outfileB > 0)
  1951.         print $0 > outfileC
  1952.     print "" > outfileC
  1953.     while (getline < outfileE > 0)
  1954.         print $0 > outfileC
  1955.     print "" > outfileC
  1956.     while (getline < outfileF > 0)
  1957.         {
  1958.         if ($0 ~ /^RETTYPE/) #start of function
  1959.             {
  1960.             #RETTYPE thefunc()
  1961.             #RETTYPE thefunc(x)
  1962.             #RETTYPE thefunc(x y z)
  1963.             
  1964.             match($0, /\(/)
  1965.             k = RSTART
  1966.             printf("%s", substr($0,1,RSTART)) > outfileC
  1967.             q = $2
  1968.             if (match(q, /\(/))
  1969.                 {
  1970.                 q = substr(q,1,RSTART-1)
  1971.                 sub(/[ \t]+/, "", q)
  1972.                 }
  1973.             protos[q] = "RETTYPE " q "("
  1974.             m = maxparms[q]+0
  1975.             $0 = substr($0,k+1)
  1976.             sub(/\)/, "")
  1977.             n = split($0, p)
  1978.             if (n > 0)
  1979.                 {
  1980.                 #output parms
  1981.                 if (m > 0)
  1982.                     {
  1983.                     printf("VARTYPE %s_c", p[1]) > outfileC
  1984.                     protos[q] = protos[q] "VARTYPE " p[1] "_c"
  1985.                     }
  1986.                 else
  1987.                     protos[q] = protos[q] "void"
  1988.                 for (i = 2; i <= m; ++i)
  1989.                     {
  1990.                     printf(", %s_c", p[i]) > outfileC
  1991.                     protos[q] = protos[q] ", " p[i] "_c"
  1992.                     }
  1993.                 protos[q] = protos[q] ");"
  1994.                 getline t < outfileF #skip over "{"
  1995.                 printf(")\n\t{\n") > outfileC
  1996.                 
  1997.                 #output decls for copies of params, and locals
  1998.                 if (m > 0)
  1999.                     {
  2000.                     printf("\tVARTYPE\t%s", p[1])  > outfileC
  2001.                     for (i = 2; i <= m; ++i)
  2002.                         printf(", %s", p[i]) > outfileC
  2003.                     printf(";\n") > outfileC
  2004.                     }
  2005.                 if (m < n)
  2006.                     {
  2007.                     printf("\tVARTYPE\t%s", p[m+1])  > outfileC
  2008.                     for (i = m+2; i <= n; ++i)
  2009.                         printf(", %s", p[i]) > outfileC
  2010.                     printf(";\n\n") > outfileC
  2011.                     }
  2012.                 else
  2013.                     printf(";\n") > outfileC
  2014.                 printf("\tentering_function();\n") > outfileC
  2015.                 #init param copies, and null the locals
  2016.                 for (i = 1; i <= m; ++i)
  2017.                     printf("\t%s = init_local(%s_c);\n", p[i],p[i]) > outfileC
  2018.                 for (i = m+1; i <= n; ++i)
  2019.                     printf("\t%s = init_local(LOCALNULL);\n", p[i]) > outfileC
  2020.                 }
  2021.             else
  2022.                 {
  2023.                 protos[q] = protos[q] "void);"
  2024.                 printf(")\n")  > outfileC
  2025.                 }
  2026.             }
  2027.         else
  2028.             print $0 > outfileC
  2029.         }
  2030.     }
  2031.  
  2032. # Output goes to outfileH
  2033. function emit_globalsEtc(    i)
  2034.     {
  2035. print "Entering"" emit_globalsEtc"
  2036.     #title
  2037.     print "/* " filename ".h */" > outfileH
  2038.     #globals - NOTE they were just sorted in emit_functions above
  2039.     #gMax = sort(globals, gIndex, "d")
  2040.     if (gMax > 0)
  2041.         {
  2042.         print "/* Global variable definitions */" > outfileH
  2043.         printf("VARTYPE\t%s", gIndex[1]) > outfileH
  2044.         for (i = 2; i <= gMax; ++i)
  2045.             {
  2046.             if (i == 5*int(i/5))
  2047.                 printf("\n") > outfileH
  2048.             printf(", %s", gIndex[i]) > outfileH
  2049.             }
  2050.         print ";" > outfileH
  2051.         print "" > outfileH
  2052.         }
  2053.     #prototypes
  2054.     #first, program init_consts_and_vars BEGIN END
  2055.     print "/* Standard function prototypes */" > outfileH
  2056.     print "RETTYPE program(void);" > outfileH
  2057.     print "void init_consts_and_vars(void);" > outfileH
  2058.     print "RETTYPE BEGIN(void);" > outfileH
  2059.     print "RETTYPE END(void);" > outfileH
  2060.     gMax = sort(protos, gIndex, "d")
  2061.     if (gMax > 0)
  2062.         {
  2063.         print "/* User function prototypes */" > outfileH
  2064.         for (i = 1; i <= gMax; ++i)
  2065.             print protos[gIndex[i]] > outfileH
  2066.         }
  2067.     }
  2068.  
  2069.